﻿using Red.Core.UndoRedo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Red.GameData.Actions
{
    /// <summary>
    /// Remove override from property
    /// </summary>
    public class RemoveArrayElement : IAction
    {
        /// <summary>
        /// Target context of objects being edited
        /// </summary>
        private Red.GameData.EditorContext _context;

        /// <summary>
        /// Id of the object to modify
        /// </summary>
        private Guid _objectID;

        /// <summary>
        /// Name of the property in the object to modify
        /// </summary>
        private string _propertyName;

        /// <summary>
        /// GUID of the array element to add
        /// </summary>
        private Guid _valueGuid;

        /// <summary>
        /// Previous value of the array element
        /// </summary>
        private string _previousValue;

        /// <summary>
        /// Get user name for this action
        /// </summary>
        /// <returns></returns>
        string IAction.GetDisplayName()
        {
            return "Remove element from '" + _propertyName + "'"; // TODO: more descriptive please :)
        }

        /// <summary>
        /// Execute action
        /// </summary>
        bool IAction.Do(Red.Core.UndoRedo.ActionHistory history, ref string errorMessage)
        {
            // get the target object
            var obj = _context.Data.Find(_objectID);
            if (obj == null)
            {
                errorMessage = "Unable to retrieve target object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // create property holder
            var prop = obj.GetProperty(_propertyName);
            if (prop == null)
            {
                errorMessage = "Unable to retrieve property '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // remove the element, value was already captured
            prop.Action_RemoveValue(_valueGuid);

            // action was successful
            return true;
        }

        /// <summary>
        /// Revert execution of the action
        /// </summary>
        bool IAction.Undo(Red.Core.UndoRedo.ActionHistory history, ref string errorMessage)
        {
            // get the target object
            var obj = _context.Data.Find(_objectID);
            if (obj == null)
            {
                errorMessage = "Unable to retrieve target object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // create property holder
            var prop = obj.GetProperty(_propertyName);
            if (prop == null)
            {
                errorMessage = "Unable to retrieve property '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // re add the array element
            if (null == prop.Action_AddValue(_previousValue, _valueGuid))
            {
                errorMessage = "Unable to undo removig element to array '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // action was successful
            return true;
        }

        /// <summary>
        /// Construct simple action
        /// </summary>
        public static RemoveArrayElement Create(EditorContext context, Raw.DataObject obj, string propertyName, Guid valueId)
        {
            // we cannot "reset" non existing properties, so it must exist
            var prop = obj.GetPropertyNoCreate(propertyName);
            if (prop == null)
                return null; // no property to reset

            // find the value being removed - it must exist in the exact property
            string previousValue = null;
            foreach (var val in prop.Values)
            {
                if (val.ID == valueId)
                {
                    previousValue = val.Value;
                    break;
                }
            }

            // no value matching given ID - somethings fishy
            if (previousValue == null)
                return null;

            var ret = new RemoveArrayElement();
            ret._context = context;
            ret._objectID = obj.ID;
            ret._valueGuid = valueId;
            ret._propertyName = propertyName;
            ret._previousValue = previousValue;
            return ret;
        }

    }

}
